sedとgrepで正規表現

sedとgrepで正規表現をお勉強しましょう

最初に正規表現をお勉強するには比較的メジャーなsedコマンドとgrepコマンドを使った方が良いかなと思いますのでこれらを利用して正規表現のお勉強をしましょう。 2つのコマンドはWindows10のWSL(Windows Subsystem for Linux)のubuntu(18.04)のものを使いますのでインストールして下さい。

Linuxを使用しますので文字コードはUTF-8、改行コードはLF(0x0a)になります。
ご自身でテキストファイルを作成するときはご注意下さい。

sedコマンドの文字列置換機能を利用します。 置換機能を用いることでどの部分がマッチしたかを確認(推測)できます。 主にこちらを使います。 grepコマンドは文字列を検索をするだけのときに使います。


sedのコマンドは下記のようになります。

sed -E 's/検索用正規表現/置換文字列/g' 置換対象ファイル名

     -E   拡張正規表現を用います(TEditorMXと同様なものになります)
     s    文字列置換を行います
     g    検索してマッチした文字列すべてを置換します



grepのコマンドは下記のようになります。

grep -E '正規表現' 検索対象ファイル名

	-E    拡張正規表現を用います(TEditorMXと同様なものになります)





項目

(1).(ピリオド)
(2)*
(3)+
(4)(pattern)
(5)x|y
(6){min,max}
(7)[xyz]
(8)^, $
(9)\d
(10)\s
(11)正規表現サンプル

  1. 数値(整数)
  2. 数値(小数点を含むことができる)
  3. 郵便番号
  4. 日付
  5. C言語の16進数
  6. 空白行(空白文字しか含まない行も含む)




(1).(ピリオド)

.(ピリオド)は改行コード以外の1文字とマッチします。


sed -E 's/./=/g' test_period_8.txt


置換前(test_period_8.txt)
a
bc
def
あいうえお


置換後

=
==
===
=====



置換文字列(=)の数を数えれば半角文字(アルファベット)とマルチバイト文字(ひらがな)に関係なく、各文字一つ一つと .(ピリオド)がマッチしていることが確認できると思います。


ページのTOPへ




(2)*

前のパターンの0回以上の繰り返しにマッチします。0回以上なので空文字列ともマッチします。 空文字列とは各文字の左側※2にあると仮定している文字数0の実体のない文字列のことです。 「空文字列とマッチ」と表現されているときは文字の左側にあると仮定している文字数0の実体のない文字列とマッチしているということです。

※2
正確には文字の周りのあらゆるところにあるとされていますが処理の都合上、文字の左側にのみあるものと仮定しています...しているのではないかと思われます。



sed -E 's/.*/=/g' test_period_8.txt

置換前(test_period_8.txt)
a
bc
def
あいうえお


置換後

=
=
=
=

となります。ちょっと話が脱線しますが、これと同様のことをTEditorMXで実行すると結果が異なり以下のようになります。

==
==
==
==
=

これは『仕様の違い』または『解釈の違い』だと思います。 sedではマッチした文字列が行末まで行くと次の行から検索を開始するのだと思われます。 そのため置換文字列(=)が各行1つしかないのだと思われます。
それに対してTEditorMXはマッチした文字列が行末まで行ったとしても行末から検索を開始します。 そのため行末の空文字列とマッチするので置換文字列(=)が各行2つになります。
で、さらにTEditorMXでは5行目にも置換文字列(=)が1つあります。 これはファイルの最後にEOF(End Of File 0x1a)があるものとして処理しているためEOFの左側の空文字列とマッチして置換されるためです。 この辺の微妙な違いについては、どちらが良いかは使う人の好みかもしれません。 ちなみにTEditorMXでsedと同じような結果を得るには下記のようにすればOKです。

検索文字列

.*(\r\n)

\r\nは改行コードです。改行コードまで記述すれば1行全体を置換できます。


置換文字列

=\r\n

または

=$1

$1は後方参照です。 この場合は改行コードになります。


置換後

=
=
=
=



ページのTOPへ




(3)+

前のパターンの1回以上の繰り返しにマッチします。1回以上なので空文字列とはマッチしません。

sed -E 's/.+/=/g' test_period_8.txt

置換前(test_period_8.txt)
a
bc
def
あいうえお


置換後

=
=
=
=

となります。


ページのTOPへ




(4)(pattern)

グルーピング。patternをひとまとまりの正規表現とします。 例えば (abc)+ とした場合には、1個以上の abc とマッチしますので、


置換前(test_group1_8.txt)

abc
abcabc
abcabcabc

の何れの abc にもマッチします。

sed -E 's/(abc)+/=/g' test_group1_8.txt
=
=
=


また、優先順位を替えるためにも使用できます。


置換前(test_group2_8.txt)

東京ドーム
東京タワー
東京駅
東京スカイツリー
東京都

の中から「東京スカイツリー」と「東京駅」を検索したい場合を考えます。

東京スカイツリー|駅

と記述してしまうと「東京スカイツリー」と「駅」にマッチして上手く検索できません。
そこでグルーピングを用いて、

東京(スカイツリー|駅)

と記述すると今度は「東京スカイツリー」と「東京駅」の両方を上手く検索することができます。

sed -E 's/東京(スカイツリー|駅)/=/g' test_group2_8.txt
東京ドーム
東京タワー
=
=
東京都

となります。 マッチした『東京駅』と『東京スカイツリー』が『=』に置換されました。


ページのTOPへ




(5)x|y

正規表現 x または y にマッチします(OR)。

sed -E 's/def|jkl/=/g' test_or_8.txt

置換前(test_or_8.txt)

abc
def
ghi
jkl
mno

置換後

abc
=
ghi
=
mno

となります。 defjkl にマッチしていますね。


ページのTOPへ




(6){min,max}

直前の正規表現の指定回数(min以上、max以下)の繰り返しにマッチします。 {number} と指定するとnumber回ちょうどの繰り返しとマッチします。



sed -E 's/(abc){2,3}/=/g' test_repeat1_8.txt

置換前(test_repeat1_8.txt)

abc
abcabc
abcabcabc
abcabcabcabc

置換後

abc
=
=
=abc

となります。2回、または3回のabcの繰り返しとマッチしていることが確認できました。


ページのTOPへ




(7)[xyz]

キャラクタリスト。指定されたxyzの中の何れかにマッチします。 ハイフン(-)で範囲指定することも可能です。[0-9]と記述すると数字1文字にマッチしますし、[A-Za-z]と記述しますとアルファベットの1文字とマッチします。 もちろんマルチバイト文字も使えます。


否定
キャラクタリストの先頭に ^ を置くと否定になります。 例えば [^0-9] と記述しますと数字以外の文字とマッチしますし、[^A-Za-z]と記述しますとアルファベット以外の文字とマッチします。


sed -E 's/[0-5]/=/g' test_charlist_8.txt
置換前(test_charlist_8.txt)
0123456789
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
ぁあぃいぅうぇえぉお
ががきぎぐけけげこご

置換後

======6789
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
ぁあぃいぅうぇえぉお
ががきぎぐけけげこご

先頭行の0~5が = に置換されました。


ページのTOPへ




(8)^, $

^ は行頭にマッチします。
$ は改行コードの直前、改行コードが無いときは行末にマッチします。


テキストファイル(test_sample1_8.cpp)から行頭にHANDLEという文字列がある行をgrepコマンドを使って検索してみます。
grep ^HANDLE test_sample1_8.cpp
HANDLE OpenInFile( char *lpFileName, BOOL fInOutFile )
HANDLE OpenOutFile( char *lpFileName )

という結果になると思います。
また、行末が e; で終わっている行を検索すると、

grep 'e;$' test_sample1_8.cpp
        HANDLE  hOpenFile;
        HANDLE  hOpenFile;
        int     num, lp, size;
        DWORD   readSize, writeSize;
        checkSum = (unsigned char)size;
        DWORD   readSize, writeSize;
        HANDLE  hInFile, hOutFile;
        DWORD   readSize, writeSize;
        unsigned long           line;
                fInOutFile = false;
                        fInOutFile = true;
                fInOutFile = true;
                                fError = true;
                        fError = true;
                        fError = true;

という結果になると思います。 全て行末が e; という文字で終わっていることが確認できますね。




ページのTOPへ




(9)\d

アラビア数字[0-9]1文字とマッチします。


ページのTOPへ




(10)\s

空白文字[ \f\n\r\t\v]とマッチします。


ページのTOPへ



(11)正規表現サンプル

1.数値(整数)
[+-]?\d+
(\+|-)?\d+

+10
-5
100

などの整数値にマッチします。

ページのTOPへ



2.数値(小数点を含むことができる)

[+-]?\d+(\.\d*)?
(\+|-)?\d+(\.\d*)?

+10
-5
100

などの整数値の他に、

+98.6
-1988.35
2056.324

などの小数値にもマッチします。


ページのTOPへ



3.郵便番号

\d{3}-\d{4}

123-4567

のような郵便番号にマッチします。


ページのTOPへ



4.日付

\d{4}/\d{1,2}/\d{1,2}

2019/1/10
1930/12/31

のような日付にマッチします。


ページのTOPへ



5.C言語の16進数

0x[0-9a-fA-F]+

0x5f
0xab16
0xFFEE0099

のような16進数にマッチします。


ページのTOPへ



6.空白行(空白文字しか含まない行も含む)

^\s*$

空白行、または空白文字しか含まない行とマッチします。

ページのTOPへ






メニュー